package com.webapp.helper;


import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.codec.binary.Base64;

import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Maps;
import com.webapp.model.MessageDigestUtil;

public class RSAUtil {

	private static final int KEYSIZE = 2048;

	private static final String KEY_ALGORITHM = "RSA";
	private static final String SIGNATURE_ALGORITHM = "SHA256withRSA";

	public static final String DEFAULT_SEED = "$%^*%^()(ED47d784sde78";

	public static final String PUBLIC_KEY = "PublicKey";
	public static final String PRIVATE_KEY = "PrivateKey";

	/**
	 * 生成秘钥
	 * 
	 * @param seed 种子
	 * @return
	 * @throws Exception
	 */
	public static Map<String, Key> initKey(String seed) throws Exception {
//	        LOGGER.info("生成密钥");
		System.out.println("生成秘钥");
		KeyPairGenerator keygen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
		SecureRandom secureRandom = new SecureRandom();
		// 如果指定seed，那么secureRandom结果是一样的，所以生成的公私钥也永远不会变
//			secureRandom.setSeed(seed.getBytes());
		// Modulus size must range from 512 to 1024 and be a multiple of 64
		keygen.initialize(KEYSIZE, secureRandom);
		KeyPair keys = keygen.genKeyPair();
		PrivateKey privateKey = keys.getPrivate();
		PublicKey publicKey = keys.getPublic();
		Map<String, Key> map = new HashMap<String, Key>(2);
		map.put(PUBLIC_KEY, publicKey);
		map.put(PRIVATE_KEY, privateKey);
		return map;
	}

	/**
	 * 生成默认秘钥
	 * 
	 * @return
	 * @throws Exception
	 */
	public static Map<String, Key> initKey() throws Exception {
		return initKey(DEFAULT_SEED);
	}

	/**
	 * 取得私钥
	 * 
	 * @param keyMap
	 * @return
	 * @throws Exception
	 */
	public static String getPrivateKey(Map<String, Key> keyMap) throws Exception {
		Key key = (Key) keyMap.get(PRIVATE_KEY);
		// base64加密私钥
		return encryptBASE64(key.getEncoded());
	}

	/**
	 * 取得公钥
	 * 
	 * @param keyMap
	 * @return
	 * @throws Exception
	 */
	public static String getPublicKey(Map<String, Key> keyMap) throws Exception {
		Key key = (Key) keyMap.get(PUBLIC_KEY);
		// base64加密公钥
		return encryptBASE64(key.getEncoded());
	}

	/**
	 * 用私钥对信息进行数字签名
	 * 
	 * @param data       加密数据
	 * @param privateKey 私钥-base64加密的
	 * @return
	 * @throws Exception
	 */
	public static String signByPrivateKey(byte[] data, String privateKey) throws Exception {
		System.out.println("用私钥对信息进行数字签名");
		byte[] keyBytes = decryptBASE64(privateKey);
		PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
		KeyFactory factory = KeyFactory.getInstance(KEY_ALGORITHM);
		PrivateKey priKey = factory.generatePrivate(keySpec);// 生成私钥
		// 用私钥对信息进行数字签名
		Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
		signature.initSign(priKey);
		signature.update(data);
		return encryptBASE64(signature.sign());

	}

	/**
	 * BASE64Encoder加密
	 * 
	 * @param data 要加密的数据
	 * @return 加密后的字符串
	 */
	private static String encryptBASE64(byte[] data) {
		return new String(Base64.encodeBase64(data));
	}

	private static byte[] decryptBASE64(String data) {
		return Base64.decodeBase64(data);
	}

	public static boolean verifyByPublicKey(byte[] data, String publicKey, String sign) throws Exception {
		byte[] keyBytes = decryptBASE64(publicKey);
		X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
		KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
		PublicKey pubKey = keyFactory.generatePublic(keySpec);
		Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
		signature.initVerify(pubKey);
		signature.update(data);
		return signature.verify(decryptBASE64(sign)); // 验证签名
	}

	public static void main(String[] args) throws Exception {
		String signStr = "testcontent17652ohkjs";
		System.out.println(signStr);
		Map<String, Key> keyMap = initKey();// 构建密钥
		PublicKey publicKey = (PublicKey) keyMap.get(PUBLIC_KEY);
		PrivateKey privateKey = (PrivateKey) keyMap.get(PRIVATE_KEY);
		System.out.println("私钥format：{}" + privateKey.getFormat());
		System.out.println("公钥format：" + publicKey.getFormat());
		System.out.println("私钥string：" + getPrivateKey(keyMap));
		System.out.println("公钥string：" + getPublicKey(keyMap));
		// 产生签名
		String sign = signByPrivateKey(signStr.getBytes(), getPrivateKey(keyMap));
		System.out.println("签名sign=" + sign);
		// 验证签名
		boolean verify1 = verifyByPublicKey(signStr.getBytes(), getPublicKey(keyMap), sign);
		System.out.println("经验证数据和签名匹配：" + verify1);

		test();

	}

	private static void test() throws Exception {
		String privateKey = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDPq651FjlA3KPMNP573D5HYlA1kjvgBr7xDuN0ss2tUYOfM6oOE42ucQZoaSa35acUce+4zSSTQm3bLsTIH/3Hm1BY0hfnkrSBPOoAr9JVZhafRB7dQDIeJSc/fQadxNbKGi4qZUkO90Jkh5RcSU/p3ScSNZzkronfDcPvKkZxU8AqtTD1yOdijT+De4MstzyYMHfv/UKb7tHA8abJNuX35xwJFxzV+xxmnSJItbNi0f462Bu9GMZla/FYdLlf088ajxh955gCdYa+okpF3/352hFC0+A9/WUEzdzSkcgkjbkSQTmqXgDNP9TX1zIkCj1c/04X4baHneUslXRT+eMvAgMBAAECggEAPxsRgX0GWuJxV92Gs4bC2hhS/WR5k2MZZNE8Zzrqa0+I6rjdZTel5ytrYhEJ9fnwYrMYwJR+F82o6mD05Udra9uTd9on73PSLC+hgCHtjYvfNfiSVHNsh2KM4asRdqHZD0MTYkizAbw7TacxezW/9fYBKHRoP8mWFdTuBGBZVZgse2tbRUDniM7QdGBmDT6H8wNl25CKoUm8pxUBCbPrtjTh4BFhuilrq+iEVvZPBEtH70OFehK/G21FfI1ouuRNb2cUArgmlnnrKcN1+3XdzXSNQsxWnBZkrVLaRFDXRfCI0BJNE2bPiSfwxji42LWjR1uKdyjMaFMDaMYMrP4aSQKBgQDoHNmf6FTdGIeLdjqSHafYS+1Hg3vtMYmOPjzmx3MKopdoyEU1di4HRFhzGFjhjnzezSRvNmfJjqEmmGD8SRIJbN/DPMC8p1F/R8O9hOBc6wwE2ff3dRyFa7Oq82OhUPpz/BCESDimplsL9C9PPcwowNnuMDG2YFhIr/iz/MjK+wKBgQDlCuPtFXjqMeB1yA8f2rIabZ2i0VTxsQo3EdIyzXJ+ld9cznLvuQXw1AHCirWepbsLUR7BoDR2Zy7xjD+iMXFWJ8wb9skhOcoQcOJH6xlzYZWLDIeDbuvxvVUtWET/58xPHkzR2OyWP21T2IRusB5HPpEMHAqAtgRnNQGQfr+SXQKBgQCOUspaU8Jdg6HxMMB/QbHeXcgTlprReROIZb9AHsH6nnHKrSpKurlEeXLmt+IgBBerIgyaKLkBDPThToQBjeiCYQDfnQvtYYcGTYHHXoeYUgOfoet7D5M6eCzFwNGxY47+uWuDQSmDffPL46FyrEjYIFBAzcpdsrvPbh9IddLFKwKBgQCJls4u2MxHG2k0N9bmEtEU0S515Xw6qFhzlnAH9qTF6DBCpv4ihapM7n6UKBFMWVCQTs3EEQIS8o8fqVl8jGkCEWwqjEhsfjOlRrqX62HhjwhvfDpXuSVhlZP6ZmEkvVFdYd1R3hbZdwas7I85kvDNaYdml92zTiQ8/3mOHKXmPQKBgHhFPQPCfyPxktTQDvz1NXZ4H+jH6t75ymXzqhOt3IYBGTk394X67r9R9dKFlDEkCwVyYvrEllAMiy31IMyihYYP4L2FHuImfOpY78Ydd3NJUIJ1fZVZ+9IaoQxnVTlvULq5UNFNkjA+qb4DNHKqLti0+ZtOV6uuVEMXfXwZtCOa";
		String authcode = "6219760850804724334";
		// 产生签名
		String qrNoIdentifier = MessageDigestUtil.getSHA256Digest(authcode);
		Map<String, String> map = Maps.newHashMap();
		map.put("qrNoIdentifier", qrNoIdentifier);
		StringBuilder signStr = new StringBuilder("qrNoIdentifier=");
		signStr.append(qrNoIdentifier);
		String sign = signByPrivateKey(signStr.toString().getBytes(), privateKey);
		System.out.println("签名sign=" + sign);
		map.put("signature", sign);
		String jsonStr = JSONObject.toJSONString(map);
		System.out.println("get info request params=" + jsonStr);
//	        // 验证签名
		boolean verify1 = verifyByPublicKey(signStr.toString().getBytes(),
				"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz6uudRY5QNyjzDT+e9w+R2JQNZI74Aa+8Q7jdLLNrVGDnzOqDhONrnEGaGkmt+WnFHHvuM0kk0Jt2y7EyB/9x5tQWNIX55K0gTzqAK/SVWYWn0Qe3UAyHiUnP30GncTWyhouKmVJDvdCZIeUXElP6d0nEjWc5K6J3w3D7ypGcVPAKrUw9cjnYo0/g3uDLLc8mDB37/1Cm+7RwPGmyTbl9+ccCRcc1fscZp0iSLWzYtH+OtgbvRjGZWvxWHS5X9PPGo8YfeeYAnWGvqJKRd/9+doRQtPgPf1lBM3c0pHIJI25EkE5ql4AzT/U19cyJAo9XP9OF+G2h53lLJV0U/njLwIDAQAB",
				sign);
		System.out.println("经验证数据和签名匹配：" + verify1);
	}

}
